{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# Python枚举类定义和使用\n",
    "Python 3.4 中新增加了 Enum 枚举类。也就是说，对于这些实例化对象个数固定的类，可以用枚举类来定义。"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [],
   "source": [
    "from enum import Enum\n",
    "\n",
    "\n",
    "class Color(Enum):\n",
    "    # 为序列值指定value值\n",
    "    red = 1\n",
    "    green = 2\n",
    "    blue = 3"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "如果想将一个类定义为枚举类，只需要令其继承自 enum 模块中的 Enum 类即可\n",
    "在 Color 枚举类中，red、green、blue 都是该类的成员（可以理解为是类变量）。注意，枚举类的每个成员都由 2 部分组成，分别为 name 和 value，其中 name 属性值为该枚举值的变量名（如 red），value 代表该枚举值的序号（序号通常从 1 开始）。"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Color.red\n",
      "Color.red\n",
      "Color.red\n",
      "1\n",
      "red\n",
      "Color.red\n",
      "Color.green\n",
      "Color.blue\n"
     ]
    }
   ],
   "source": [
    "# 调用枚举成员的 3 中方式\n",
    "print(Color.red)\n",
    "print(Color['red'])\n",
    "print(Color(1))\n",
    "# 调取枚举成员中的value和name\n",
    "print(Color.red.value)\n",
    "print(Color.red.name)\n",
    "# 遍历枚举类中所有成员\n",
    "for color in Color:\n",
    "    print(color)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "枚举类成员之间不能比较大小，但可以用 == 或者 is 进行比较是否相等，例如："
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "print(Color.red == Color.green)\n",
    "print(Color.red.name is Color.green.name)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "需要注意的是，枚举类中各个成员的值，不能在类的外部做任何修改，也就是说，下面语法的做法是错误的："
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "Cannot reassign members.",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mAttributeError\u001B[0m                            Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[12], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m Color\u001B[38;5;241m.\u001B[39mred \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m3\u001B[39m\n",
      "File \u001B[1;32mD:\\dev\\miniconda3\\envs\\python-study\\lib\\enum.py:480\u001B[0m, in \u001B[0;36mEnumMeta.__setattr__\u001B[1;34m(cls, name, value)\u001B[0m\n\u001B[0;32m    478\u001B[0m member_map \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mcls\u001B[39m\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__dict__\u001B[39m\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124m_member_map_\u001B[39m\u001B[38;5;124m'\u001B[39m, {})\n\u001B[0;32m    479\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m name \u001B[38;5;129;01min\u001B[39;00m member_map:\n\u001B[1;32m--> 480\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mAttributeError\u001B[39;00m(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mCannot reassign members.\u001B[39m\u001B[38;5;124m'\u001B[39m)\n\u001B[0;32m    481\u001B[0m \u001B[38;5;28msuper\u001B[39m()\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__setattr__\u001B[39m(name, value)\n",
      "\u001B[1;31mAttributeError\u001B[0m: Cannot reassign members."
     ]
    }
   ],
   "source": [
    "Color.red = 3"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "Python 枚举类中各个成员必须保证 name 互不相同，但 value 可以相同"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Color.red\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "class Color(Enum):\n",
    "    red = 1\n",
    "    green = 1\n",
    "    blue = 3\n",
    "\n",
    "print(Color.green)\n",
    "print(Color.green == Color.red)\n",
    "print(Color.green is Color.red)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "如果想避免发生这种情况，可以借助 @unique 装饰器，这样当枚举类中出现相同值的成员时，程序会报 ValueError 错误。"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "duplicate values found in <enum 'Color'>: green -> red",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mValueError\u001B[0m                                Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[18], line 5\u001B[0m\n\u001B[0;32m      1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01menum\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m unique\n\u001B[0;32m      4\u001B[0m \u001B[38;5;129;43m@unique\u001B[39;49m\n\u001B[1;32m----> 5\u001B[0m \u001B[38;5;28;43;01mclass\u001B[39;49;00m\u001B[43m \u001B[49m\u001B[38;5;21;43;01mColor\u001B[39;49;00m\u001B[43m(\u001B[49m\u001B[43mEnum\u001B[49m\u001B[43m)\u001B[49m\u001B[43m:\u001B[49m\n\u001B[0;32m      6\u001B[0m \u001B[43m    \u001B[49m\u001B[43mred\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m1\u001B[39;49m\n\u001B[0;32m      7\u001B[0m \u001B[43m    \u001B[49m\u001B[43mgreen\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m1\u001B[39;49m\n",
      "File \u001B[1;32mD:\\dev\\miniconda3\\envs\\python-study\\lib\\enum.py:1022\u001B[0m, in \u001B[0;36munique\u001B[1;34m(enumeration)\u001B[0m\n\u001B[0;32m   1019\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m duplicates:\n\u001B[0;32m   1020\u001B[0m     alias_details \u001B[38;5;241m=\u001B[39m \u001B[38;5;124m'\u001B[39m\u001B[38;5;124m, \u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;241m.\u001B[39mjoin(\n\u001B[0;32m   1021\u001B[0m             [\u001B[38;5;124m\"\u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m -> \u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m\"\u001B[39m \u001B[38;5;241m%\u001B[39m (alias, name) \u001B[38;5;28;01mfor\u001B[39;00m (alias, name) \u001B[38;5;129;01min\u001B[39;00m duplicates])\n\u001B[1;32m-> 1022\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mduplicate values found in \u001B[39m\u001B[38;5;132;01m%r\u001B[39;00m\u001B[38;5;124m: \u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m'\u001B[39m \u001B[38;5;241m%\u001B[39m\n\u001B[0;32m   1023\u001B[0m             (enumeration, alias_details))\n\u001B[0;32m   1024\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m enumeration\n",
      "\u001B[1;31mValueError\u001B[0m: duplicate values found in <enum 'Color'>: green -> red"
     ]
    }
   ],
   "source": [
    "from enum import unique\n",
    "\n",
    "\n",
    "@unique\n",
    "class Color(Enum):\n",
    "    red = 1\n",
    "    green = 1\n",
    "    blue = 3\n",
    "\n",
    "print(Color.green)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "除了通过继承 Enum 类的方法创建枚举类，还可以使用 Enum() 函数创建枚举类。"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Color.red\n",
      "Color.red\n",
      "Color.green\n",
      "Color.blue\n"
     ]
    }
   ],
   "source": [
    "Color = Enum(\"Color\", ('red', 'green', 'blue'))\n",
    "print(Color.red)\n",
    "\n",
    "for color in Color:\n",
    "    print(color)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}